#!/usr/bin/python
# -*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__date__ = u"15 oct. 2009"
__author__ = u"guillaume"

__all__ = [u'QIOHandler', u'LockHandler',
           u'ShellRun', u'PythonRun', u'Thread']


from pyLot.interfaces import (CommonRunInterface, LockHandlerInterface,
                              LockInterface, IOHandlerInterface,
                              WriterInterface)
from pyLot.core import check_type, Container

from Qt4 import QtGui
from Qt4.QtCore import QProcess, QThread, QMutex, SIGNAL
#from collectiontools import DialogCollectionEditor

from _pylot.qtgui.styles.charformats import PYLOT_CHAR_FORMATS
from _pylot.qtgui.widgets.gui_textview import GuiTextView
from _pylot.qtgui.widgets.gui_statusbar import GuiStatusBar
from _pylot.qtgui.widgets.gui_containereditor import GuiContainerEditor
from _pylot.qtgui.widgets.gui_simpledialog import GuiSimpleDialog


class QIOHandler (IOHandlerInterface):

  def __init__ (self, stdout=None, stderr=None, status=None,
                display_level=u'standard',
                char_formats=PYLOT_CHAR_FORMATS):
    self.char_formats = char_formats

    # define default writers
    if stdout is None :
      stdout = GuiTextView(self.char_formats)
    else :
      check_type(u'stdout', stdout, WriterInterface)

    if stderr is None :
      stderr = GuiTextView(self.char_formats)
    else :
      check_type(u'stderr', stderr, WriterInterface)

    if status is None :
      status = GuiStatusBar(self.char_formats)
    else :
      check_type(u'status', status, WriterInterface)
      check_type(u'status', status, QtGui.QStatusBar)

    super(QIOHandler, self).__init__(stdout, stderr, status,
                                    display_level=display_level)

    self.resetToDefaultWriters()

  def _writePopUp(self, text, title, style=u'std'):
    if style == u'warn':
      dialog = QtGui.QMessageBox.warning(None, title, text)
    else :
      dialog = QtGui.QMessageBox.information(None, title, text)

  def _rawInput (self, text):
    text, ok = QtGui.QInputDialog.getText(None, tr_(u"Setting value"), text)
    if ok :
      return unicode(text)
    else :
      self._rawInput(text)

  def _editData (self, data_obj, text):
    editor = GuiContainerEditor(data_obj)
    dialog = GuiSimpleDialog(widget=editor)
    if dialog.exec_() == QtGui.QDialog.Accepted :
      pass

  def _yesNoQuestion(self, text):
    rep = QtGui.QMessageBox.warning(None, tr_(u"Question"), text,
      QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel)
    if rep == QtGui.QMessageBox.Ok :
      return True
    else :
      return False

  def _editDatum(self, datum, text):
    container = Container(data=[datum])
    return self._editData(container, text)

  def _editContainer(self, container, text):
    return self._editData(container, text)

  def getStatusBarWidget(self):
    return self.status

class Lock (LockInterface):
  def __init__ (self):
    self.lock = QMutex()

  def acquire (self):
    self.lock.lock()

  def release (self):
    self.lock.unlock()

class LockHandler (LockHandlerInterface):

  def newLock (self):
    return Lock()

class Thread (QThread):

  def __init__ (self, python_run, parent=None):
    super(Thread, self).__init__(parent)
    self.return_code = None
    self.python_run = python_run

  def run (self):
    try :
      function, args, kargs = self.python_run.pyObjects()
      function(*args, **kargs)
    except :
      self.return_code = 1
    else :
      self.return_code = 0

  def kill (self, signal):
    self.return_code = 1
    self.exit(1)

class PythonRun (CommonRunInterface):

  def _getState (self):
    if self.thread.isRunning() :
      return self.Running
    elif self.thread.isFinished():
      return self.Finished
    else :
      return self.NotRunning

  def _getReturnCode (self):
    return self.thread.return_code

  def _kill (self, signal):
    self.thread.kill(signal)

class ShellRun (CommonRunInterface):

  def __init__ (self, thread):
    super(ShellRun, self).__init__(thread)
    self._started = False
    thread.connect(thread, SIGNAL('started()'), self._processStarted)

  def _processStarted (self):
    self._started = True

  def _getState (self):
    if self._started is False :
      return self.NotRunning
    else :
      if self.thread.state() in (QProcess.Starting, QProcess.Running) :
        return self.Running
      elif self.thread.state() == QProcess.NotRunning :
        return self.Finished
      else :
        print u'Unknown status %s %s' % (self.thread.state(),
                                        type(self.thread.state()))

  def _getReturnCode (self):
    if self.thread.exitStatus() == QProcess.NormalExit and self.thread.error() == QProcess.UnknownError :
      # UnknownError is default error() value
      # so UnknownError generally means "No Error"
      return self.thread.exitCode()
    else :
      # Application crashed, return error
      return 1

  def _terminate(self):
    self.thread.terminate()

  def _kill (self, signal):
    self.thread.kill()
